//*****************************************************************************
//
// EE 345M - Valvano
// Spring 2011
// Created by: Paul Kreter
// TA: Raffaele Cetrulo TTh 6:30 - 8:00
//
// tachometer.c - Functions for measuring the speed of a spinning object in
// revolutions per minute (RPM). Lab 6 version
//
//*****************************************************************************
#include "../inc/hw_memmap.h"
#include "../inc/hw_types.h"
#include "../driverlib/interrupt.h"
#include "../inc/hw_ints.h"
#include "../inc/hw_timer.h"
#include "../driverlib/timer.h"
#include "lm3s8962.h"
#include "tachometer.h"

int TachFlag;
unsigned long PeriodM1, PeriodM2;
unsigned long Period; // 167 ns units
unsigned long First; // Timer0A first edge
unsigned long Timeouts; // Number of timerA timeouts
//unsigned char Done; // set each rising

//*****************************************************************************
//
// Function adapted from Prof. Valvano's Lecture 16: Input Capture
//
//*****************************************************************************
void
Tachometer_Init(void)
{
	SYSCTL_RCGC1_R |= SYSCTL_RCGC1_TIMER0;// activate timer0
	SYSCTL_RCGC2_R |= SYSCTL_RCGC2_GPIOD; // activate port D
	// allow time to finish activating
	First = 0; // first will be wrong
	Period = 0;
	PeriodM1 = 0;
	PeriodM2 = 0;
	Timeouts = 0;
	TachFlag = 0;
	//Done = 0; // set on subsequent
	GPIO_PORTD_DEN_R |= 0x10; // enable digital I/O on PD4
	GPIO_PORTD_AFSEL_R |= 0x10; // enable alt funct on PD4
	TIMER0_CTL_R &= ~TIMER_CTL_TAEN; // disable timer0A during setup
	TIMER0_CFG_R = TIMER_CFG_16_BIT; // configure for 16-bit timer mode
	// configure for capture mode
	TIMER0_TAMR_R = (TIMER_TAMR_TACMR|TIMER_TAMR_TAMR_CAP);
	// configure for rising edge event
	TIMER0_CTL_R &= ~(TIMER_CTL_TAEVENT_POS|0xC);
	TIMER0_TAILR_R = TIMER_TAILR_TAILRL_M;// start value
	TIMER0_IMR_R |= (TIMER_IMR_CAEIM|TIMER_IMR_TATOIM); // enable capture match interrupt and 
	TIMER0_ICR_R = TIMER_ICR_CAECINT;// clear timer0A capture match flag
	TIMER0_CTL_R |= TIMER_CTL_TAEN; // enable timer0A 16-b, +edge, interrupts
	// Timer0A=priority 2
	NVIC_PRI4_R = (NVIC_PRI4_R&0x00FFFFFF)|0x40000000; // top 3 bits
	NVIC_EN0_R |= NVIC_EN0_INT19; // enable interrupt 19 in NVIC
	// enable timer0A interrupt
	IntEnable(INT_TIMER0A);
}

//*****************************************************************************
//
// Function adapted from Prof. Valvano's Lecture 16: Input Capture
//
//*****************************************************************************
void
Timer0A_Handler(void)
{
	if(TIMER0_MIS_R & TIMER_MIS_TATOMIS)
	{
		TIMER0_ICR_R = TIMER_ICR_TATOCINT;// acknowledge timer0A timeout
		Timeouts++;
	} else if(TIMER0_MIS_R & TIMER_MIS_CAEMIS)
	{
		TIMER0_ICR_R = TIMER_ICR_CAECINT;// acknowledge timer0A capture match
		PeriodM2 = PeriodM1;
		PeriodM1 = Period;
		Period = (First&0xFFFF)+(0xFFFF-TIMER0_TAR_R)+(0xFFFF*(Timeouts-1));// 167ns resolution
		First = TIMER0_TAR_R; // setup for next
		Timeouts = 0;
		TachFlag = 1;
		//Done = 0xFF;
	}
}

//*****************************************************************************
//
// ORIGINAL FUNCTION WRITTEN BY PAUL KRETER
//
// This function returns the Period calculated by the tachometer interrupt.
//
//*****************************************************************************
unsigned long
Tachometer_GetPeriod(void)
{
	unsigned long per;
	IntMasterDisable();
	if(Period > PeriodM1)
	{
		if(Period < PeriodM2)
			per = Period;
		else if(PeriodM1 > PeriodM2)
			per = PeriodM1;
		else
			per = PeriodM2;
	} else
	{
		if(Period > PeriodM2)
			per = Period;
		else if(PeriodM1 < PeriodM2)
			per = PeriodM1;
		else
			per = PeriodM2;	
	}
	TachFlag = 0;
	IntMasterEnable();
	return per;
}

int
Tach_Status(void)
{
	return TachFlag;
}
